home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 32 / Mac Magazin and MacEasy Magazine CD - Issue 32.iso / Grafik & Text / OzTeX3.0 / Metafont / Inputs / ec / exaccess.mf < prev    next >
Text File  |  1997-03-16  |  38KB  |  892 lines

  1. % exaccess.mf
  2. %
  3. % This file is part of ecfonts version 1.0
  4. %
  5. % Please read the files 00readme.txt, 00inst.txt, 00error.txt, and
  6. % copyrite.txt for further information
  7. %
  8. % You find some documentation in ecdoc.tex (needs LaTeX2e)
  9. %
  10. % Accessories and special definitions for polish letters
  11. % Adapted to the ec fonts by J\"org Knappen
  12. %
  13. % Copyright (c) 1992 Bogus\l{}aw Jackowski \& Marek Ry\'cko
  14. % Copyright (c) 1995, 1996, 1997 J\"org Knappen
  15. % ---------------------------------------------------------------------------
  16. % This was PL_DOD.MF ({\bif{}dodatkowy}, i.e., additional file for the Polish
  17. % extension of CM family) in text format.
  18. % ---------------------------------------------------------------------------
  19. %%{\let\:\sl
  20. %\: This file provides accessories for making Polish diacritical characters: 
  21. %\: acute accent for |"C"|, |"N"|, |"L"|, |"S"|, |"Z"|, dot accent for |"Z"|,
  22. %\: cross for |"L"| and ogonek for |"A"| and |"E"|.  In order to avoid extra
  23. %\: parameters (62 should be enough) the macros do a lot of ``clever'' stuff,
  24. %\: trying to figure out needed dimensions. This is not always a trivial
  25. %\: task and in some cases such extra parameters may prove to be unavoidable.
  26. %\: Several additional parameters may be assigned a value, prior to reading
  27. %\: the driver file, in order to override the default behaviour.
  28.  
  29. %\: One of them is
  30. %\:   --- the factor controlling the slope of accents over majuscules,
  31. %\:       |cap_flat|; if the default slope is, say, $\beta$, the resulting
  32. %\:       slope is equal to |(1-cap_flat)*|$\beta$; this parameter is used
  33. %\:       in the sources of the following fonts:
  34. %\        PLCSC10, PLDUNH10, PLTCSC10
  35.  
  36. %\: Unexpectedly difficult to program turned out to be ogoneks. We decided
  37. %\: that the best looking are ogoneks such that a single B\`ezier segment
  38. %\: describes each of ogonek's edges. This necessitated introducing many
  39. %\: parameters controlling the positions of control points (for more details
  40. %\: see comments in the section ``OGONEK ACCESSORIES''). All these
  41. %\: (optional) parameters may be splitted into three groups of importance:
  42. %\: primary, secondary and tertiary. The primary parameters are intended
  43. %\: to be ``normally'' accessible to users, the secondary ones---only in
  44. %\: case of emergency, the tertiary ones---rather not at all.
  45.  
  46. %\: The primary parameters are:
  47.  
  48. %\:   --- the factor controlling the depth of ogoneks, |depth_corr|; the
  49. %\:       resulting depth is equal to |depth_corr*desc_depth#| if the value
  50. %\:       of |depth_corr| is known, |desc_depth#| otherwise
  51. %\:   --- the factor controlling the leftmost and tip positions
  52. %\:       of an ogonek, |left_corr|, |tip_xcorr| and |tip_ycorr|;
  53. %\:       the default distances are scaled using the values of the
  54. %\:       corresponding parameters       
  55. %\:   --- the scaling factor for the top and tip breadths of an ogonek,
  56. %\:       |top_breadth_corr|, |tip_breadth_corr|
  57.  
  58. %\: Some of the primary parameters are used in the sources of the following
  59. %\: fonts:
  60. %   PLB10, PLBX5, PLBX6, PLBX7, PLBX8, PLFI10, PLITT10, PLR5, PLR6, PLR7,
  61. %   PLR8, PLR9, PLR12, PLR17, PLSL8, PLSL9, PLSL12, PLSSQ8, PLSSQI8, PLTI7,
  62. %   PLTI8, PLTI12, PLVTT10
  63.  
  64. %\: The following four parameters we regard as of a secondary importance:
  65.  
  66. %\:   --- the pen ogoneks are to be filled with, |ogonek_pen#| (this is
  67. %\:       the only sharp ogonek parameter and is used in the sources of 
  68. %\:       the {\commfont{}PLFF10} and {\commfont{}PLFI10} fonts)
  69. %\:   --- the darkness of ogoneks may be controlled using two parameters,
  70. %\:       |0<pre_lightness<1| and |0<post_lightness<1|, referring to the top
  71. %\:       and tip of an ogonek, respectively; used in {\commfont{}PLB10.MF}
  72. %\:   --- next two parameters, |pre_deflexion| and |post_deflexion|, control
  73. %\:       a rather small deflexion angle (in degrees) of the inner ogonek
  74. %\:       outline as compared to the outer one; they refere to the top and
  75. %\:       tip of an ogonek, respectively
  76.  
  77. %\: The complete list of `ogonek' parameters can be found in the section
  78. %\: ``OGONEK ACCESSORIES.''
  79.  
  80. %\: There is one more (rather unimportant) parameter, |is_smoke|. If this
  81. %\: variable is assigned a known value, `smoked' proofs will not contain
  82. %\: a rule marking the height of accented letters.
  83. %%}
  84. % ---------------------------------------------------------------------------
  85. % HISTORY
  86. %  7 Feb 1992: version 1.00
  87. % 11 Feb 1992: version 1.01
  88. %    (no changes; the new version number due to changes in \MeX{} format)
  89. % 25 May 1992: version 1.02
  90. %    The following two erroneous assignments:
  91. %|  z_a:=(x_down+the_left_pos,.5penkind); %| starting point
  92. %|  z_d:=(xpart(z_a)-.5penkind,y_right+.5penkind)+the_tip_pos; %| ending point
  93. %    changed to the following ones:
  94. %|  z_a:=(x_down+the_left_pos,ypart(ogonek_pos)); %| starting point
  95. %|  z_d:=(xpart(z_a)-.5penkind,y_right+ypart(ogonek_pos))+|
  96. %|   the_tip_pos; %| ending point
  97. %    Some comments changed.
  98. % 18 Dec 1992: version 1.03
  99. %    (no changes; the new version number due to changes in FIK_MIK.MF
  100. %    and some cosmetic changes in CMBX11.MF, CMR11.MF, CMTI11.MF, CMSL11.MF,
  101. %    CMSSBI10.MF, and POLAN.MF)
  102. % 21 Apr 1995: Adaption for dxbase and dcfonts:
  103. %    Deleted character code (those are fixed by the Cork standard)
  104. %    Deleted |improve_kerns|
  105. %    Avoid double rounding in the definition of |fisp| by defining |fisp#|
  106. %    Made |the_ogonek_depth| explicitly sharp (|the_ogonek_depth#|)
  107. %    Changed definition of |is_cap|
  108. %    Replaced all occurences of |ogonked_a| and |ogonked_e| with the
  109. %    Cork code values |oct"241"| and |oct"246"| respectively
  110. %    Replaced |dotted_Z| and |dotted_z| with |oct"233"| and |oct"273"|
  111. %    respectively
  112. %    Renamed |expansion_factor| to |expansion_faktor| because of 
  113. %    conflicting definition 
  114. %  7 May 1995 Appended material from czechoslovak fonts (csaccent.mf)
  115. % 18 May 1995 Changed |put_accent| because I want to use it twice in
  116. %    one character. To achieve this, the variables |z.top| and |z.right|
  117. %    were renamed |z[jj].top| and |z[jj].right| respectively
  118. %    Changed |is_cap| again (included |168| for l with acute)
  119. % 29 May 1995 Added accessories for the grave accent
  120. %    Changes one comment to point to dxcsc.mf instead of polkap.mf
  121. % 18 Jun 1995 Made provision in |put_cross| for the blank symbol
  122. %    Made provision in |put_dot| for turkish dotted `I'
  123. % 10 Jul 1995 Changed condition in |put_dot| to refer to |is_cap|. Needed 
  124. %    with the tc fonts.
  125. % 11 Jul 1995 Added another proviso to |put_dot| to produce floating dot
  126. % 23 Jul 1995 Added proviso in |put_cross| for recipe sign
  127. % 17 Aug 1995 Tuned height of accent again, added |hi.x_height@#+acc_height@#| 
  128. %    to the minimum condition
  129. % 14 Apr 1996 Buildt in Bogus\l{}aw Jackowski's fixes to avoid resolution
  130. %    dependent font metrics. 
  131. %    I did not apply the change to the |put_dot| macro, because there is
  132. %    no chance to keep it consistent for the floating dot accent
  133. %    Macros for processing characters twice put to |exbase.mf|
  134. % 26 Apr 1996 Put in version checking
  135. %    Moved last minute font setup to |expseudo.mf|
  136. % 10-MAY-1996 Corrected |corrital| to make use of the canonical sharp mode
  137. %    Added |version_check|
  138. % 22-DEC-1996 Moved definition of |is_small_cap| and |hi.| to |exbase.mf|
  139. %    Changed the documentation to know about ec fonts instead of dc fonts.
  140. % ---------------------------------------------------------------------------
  141. %                          VERSION CHECKING
  142. % ---------------------------------------------------------------------------
  143. version_check(1,0);  % |version_check| was introduced in dc1.3
  144. % ---------------------------------------------------------------------------
  145. %                          LAYOUT SETUP:
  146. %        (A MIXTURE OF EXTENDED CM, EXTENDED ASCII, AND ``LOCAL'')
  147. % ---------------------------------------------------------------------------
  148. % [deleted]
  149. % ---------------------------------------------------------------------------
  150. %                            EXTRA PARAMETERS
  151. % ---------------------------------------------------------------------------
  152. % [deleted and/or moved] 
  153. %
  154. % The variable |limit_dist| is set to |5/4u| in PL_DL.MF, PL_ML.MF and
  155. % PL_MLK.MF, and used in |put_accent| and |put_cross|. It was introduced
  156. % because of some funny (although troublesome) fonts. The value of |u| is
  157. % changed by |mono_adjust|, hence it is set outside |beginchar| ... |endchar|
  158. % rather than inside.
  159. numeric limit_dist;
  160. % ---------------------------------------------------------------------------
  161. %                         GENERAL PURPOSE ACCESSORIES
  162. % ---------------------------------------------------------------------------
  163. vardef is_egyptian =
  164. % |false| for most of the CM fonts, except funny fonts;
  165. % |true| for the CC fonts
  166.  serifs and (1.4max(fine#,crisp#, tiny#)<slab#) and (1.6slab#>stem#)
  167. enddef;
  168.  
  169. vardef is_bold = if serifs: (hair#+.5stem#)>1.5u# else: stem#>2u# fi\\ enddef;
  170.  
  171. vardef is_cap =
  172.   (((127 < charcode) and (charcode < 158)) or\\ 
  173.   ((191 < charcode) and (charcode < 224))) or\\
  174.   (charcode = 168) % true for l with acute
  175. enddef;
  176.  
  177. %%% top is_known
  178. %%% top fix_virgin
  179. vardef is_known z suffix $ =
  180. % an auxiliary macro for |fix_virgin z|, used also while constructing ogoneks
  181.  (known x$) or (known x$l) or (known x$r)\\ or
  182.  (known y$) or (known y$l) or (known y$r)
  183. enddef;
  184.  
  185. vardef fix_virgin z = % find a pair of virgin pairs
  186.  numeric ii,jj; jj:=1;
  187.  forever:
  188.   if is_known z[jj] or is_known z[jj+1]: % unknown gaps may occur
  189.   jj:=incr jj else: jj=ii fi; exitif known ii;
  190.  endfor;
  191.  jj:=ii+1;
  192. % now |ii| and |jj| are such that |z[ii]| and |z[jj]| are ``untouched''
  193. enddef;
  194.  
  195. %%% italcorr corrital
  196. % correction of italic correction (cf. D. E. Knuth, The \MF{}book, p. 105):
  197. vardef corrital z suffix $ =
  198. % |z$| is the rightmost position of a pen (in accent path)
  199.  if known sharp_calc:
  200.   if not monospace:
  201.    save charic_; charic_=(rt(x$)-r)/hppp+slant*y$/vppp+.5u#;
  202.    if charic_>charic: charic:=charic_; fi
  203.   fi
  204. %| else: %| |charic=mono_charic#|, do nothing
  205.  fi
  206. enddef;
  207.  
  208. %%% top prepare_pen
  209. def prepare_pen suffix $ =
  210. %%% fine $ %%%% temporary MFT convention
  211.   if $>fudged.hair: $:=fudged.hair; fi
  212.   $.breadth:=$;
  213.   pickup if $=0: nullpen else: pencircle scaled $; $:=$-eps fi;
  214.   $.nib:=savepen; breadth_[$.nib]:=$;
  215.   forsuffixes $$=lft,rt,top,bot: shiftdef($.$$,$$ 0); endfor
  216. %%% qq $ %%%% ordinary MFT convention
  217. enddef;
  218.  
  219. % The proportion of |vair/stem| depends drastically on resolution;
  220. % e.g., for 300 dpi cmbx10 |vair=1| and |stem=5|, for 746 dpi cmbx10
  221. % (300 dpi, magstep 5) |vair=4| and |stem=12|, while, sharply speaking,
  222. % |stem#/vair#=3.15381|; hence a new variable |xvair| has been introduced
  223. % to be used in some crucial places instead of |vair|.
  224. vardef xvair = stem*vair#/stem# enddef;
  225. % ---------------------------------------------------------------------------
  226. %                          ACCENT ACCESSORIES
  227. % ---------------------------------------------------------------------------
  228. % |the_cap_flat| is a factor controlling the flatness of accents over
  229. % majuscules; a default value may be overriden by assigning a value to the
  230. % variable |cap_flat| (cf. also |the_|... macros in ogonek accessories).
  231. vardef the_cap_flat =
  232.  if known cap_flat: cap_flat elseif serifs and hefty: 1/5 else: 1/3 fi
  233. enddef;
  234. % ---------------------------------------------------------------------------
  235. % The |hpos_corr| variable is an optional parameter to |put_ogonek|, meant
  236. % to be set locally inside |beginchar| ... |endchar|, if a horizontal
  237. % correction of the accent position is needed:
  238. numeric hpos_corr;
  239. % ---------------------------------------------------------------------------
  240. %%%% temporary MFT convention:
  241. %%% top x_height diam a_wd a_ht i_ht u asc_height cap_A_wd
  242. % width of the acute accent:
  243. vardef a_wd@# = 9hi.u@# enddef;
  244. % height of the acute accent:
  245. vardef a_ht@# = 
  246.  min(asc_height@#,2hi.x_height@#,hi.x_height@#+acc_height@#) enddef;
  247. % height of the letter `i':
  248. vardef i_ht@#(suffix diam) =
  249.  if is_small_cap: a_ht@# % usually there is no dot over a small cap `i'
  250.  else: min(asc_height@#, 10/7hi.x_height@#+.5diam@#) fi
  251. enddef;
  252. % width of the letter `A' (used in |put_ogonek|):
  253. vardef cap_A_wd@# = 13u@# enddef;
  254. %%%% ordinary MFT convention:
  255. %%% qq x_height diam a_wd a_ht i_ht u asc_height cap_A_wd
  256.  
  257. def mark_height(expr sharp_h)=
  258. % |sharp_h| is the height of an accented minuscule
  259.  if known sharp_calc:
  260.   charht:=if is_cap: h/vppp else: sharp_h fi;
  261.   if\\ (proofing>0) and is_cap:
  262. % BJ likes to have proofs vertically aligned (somehow):
  263.    proofoffset(0,h-charht*vppp-1mm);
  264.   fi
  265.  fi
  266. % say earlier, e.g., |is_smoke=1| if you're making `smoked' proofs
  267. % and you don't like to have a rule marking the height
  268.  if unknown is_smoke:
  269.   if proofing>0: proofrule((l+w/2,charht*hppp)t_,(r+u,charht*hppp)t_); fi
  270.   if displaying>0: screenrule((l+w/2,charht*hppp)t_,(r+u,charht*hppp)t_); fi
  271.  fi
  272. enddef;
  273.  
  274. def fix_acc_pairs =
  275.  fix_virgin z;
  276.  begingroup
  277. % excerpt from |beginchar|:
  278.   save w,h; w=round(a_wd); h=round(a_ht);
  279. % excerpt from |mono_adjust|:
  280.   if monospace:
  281.    save u_; numeric u_; u_:=hi.u#; save u; u#:=u_;
  282.    numeric expansion_faktor;
  283.    mono_charwd#=2 hi.letter_fit#+expansion_faktor*a_wd#;
  284.    hi.u:=u#*expansion_faktor*hppp;
  285.    w:=mono_charwd-shrink_fit-2 hi.letter_fit;
  286.   fi
  287. % end of the excerpts
  288.   numeric accent_gap,mid_stem; mid_stem=2/3[stem,hi.stem];
  289.   if serifs:
  290.    pickup crisp.nib;
  291.    x[jj]'=hround(w-2hi.u)-.5mid_stem; x[jj]':=x[jj]'-2/3[x[jj]',w-x[jj]'];
  292.    y[jj]'=h-.5mid_stem+eps-max(2/3[h,hi.x_height],hi.x_height+o+hair);
  293.    accent_gap=a_ht-(y[jj]'+.5mid_stem)-hi.x_height;
  294.    bot z[ii]=round(accent_hpos,
  295.     accent_gap+if is_cap: cap_height else: hi.x_height fi);
  296.    z[jj]=z[ii]+(z[jj]'
  297.     if is_cap: rotated (-the_cap_flat*angle(z[jj]')) fi);
  298.    numeric theta; theta=angle(z[ii]-z[jj])+90;
  299.    pos[jj](mid_stem,theta); pos[ii](hair,theta);
  300.   else:
  301.    pickup fine.nib;
  302.    rt x[jj]'r=hround(.5w-1.25hi.u);
  303.    top y[jj]'=h-vround(2/3[h,hi.x_height]);
  304.    z[ii]'=origin; pos[jj]'(mid_stem,0); pos[ii]'(vair,0);
  305.    accent_gap=a_ht-y[jj]'-hi.x_height;
  306.    if is_cap:
  307.     numeric beta; beta=-the_cap_flat*angle(z[jj]'-z[ii]');
  308.     z[ii]=round(accent_hpos,accent_gap+cap_height);
  309.     z[jj]=z[ii]+(z[jj]' rotated beta);
  310.     y[jj]r=y[jj]l=y[jj]; y[ii]r=y[ii]l=y[ii];
  311.     for xx:=jj,ii: forsuffixes $:=l,r:
  312.      (z[xx]$-z[ii]) rotated -beta=whatever[z[jj]'$,z[ii]'$];
  313.     endfor\\ endfor
  314.    else:
  315.     for xx:=jj,ii: forsuffixes $:=r, ,l:
  316.      z[xx]$=z[xx]'$+round(accent_hpos,
  317.       accent_gap+if is_small_cap: cap_height else: x_height fi);
  318.     endfor\\ endfor
  319.    fi
  320.   fi
  321.  endgroup;
  322. enddef;
  323.  
  324. def put_accent=
  325.  numeric accent_hpos;
  326.  accent_hpos=.5w - if is_cap: .75 else: .5 fi\\ u
  327.   if known hpos_corr: +hpos_corr fi;
  328.  fix_acc_pairs; % |fix_acc_pairs| uses private values of |w|, |h| \& |u|
  329.  numeric hpos_corr; % |hpos_corr| is local: forget its value
  330. % draw the diagonal:
  331.  if serifs:
  332.   pickup crisp.nib; filldraw circ_stroke (z[jj]e--z[ii]e);
  333.   z[jj].right=directionpoint up of (z[jj]r{z[jj]r-z[ii]r}..{z[ii]l-z[jj]l}z[jj]l);
  334.   z[jj].top=directionpoint left of (z[jj]r{z[jj]r-z[ii]r}..{z[ii]l-z[jj]l}z[jj]l);
  335.  else:
  336.   pickup fine.nib; filldraw stroke (z[jj]e--z[ii]e);
  337.   z[jj].right=z[jj].top=z[jj]r;
  338.  fi
  339.  corrital z[jj].right; % correct italic correction
  340. % adjust and save height (it is used in the program for the dotted `Z'):
  341.  h:=if is_cap: y[jj].top else: a_ht fi; 
  342.  if known sharp_calc: saved_height:=h; fi
  343.  mark_height(a_ht#); 
  344.  penlabels([ii],[jj]);
  345. enddef;
  346. % ---------------------------------------------------------------------------
  347. %                           GRAVE ACCENT ACCESSORIES
  348. % ---------------------------------------------------------------------------
  349. % This section borrows heavily from the (acute) accent accessories
  350. def fix_grav_pairs =
  351.  fix_virgin z;
  352.  begingroup
  353. % excerpt from |beginchar|:
  354.   save w,h; w=round(a_wd); h=round(a_ht);
  355. % excerpt from |mono_adjust|:
  356.   if monospace:
  357.    save u_; numeric u_; u_:=hi.u#; save u; u#:=u_;
  358.    numeric expansion_faktor;
  359.    mono_charwd#=2 hi.letter_fit#+expansion_faktor*a_wd#;
  360.    hi.u:=u#*expansion_faktor*hppp;
  361.    w:=mono_charwd-shrink_fit-2 hi.letter_fit;
  362.   fi
  363. % end of the excerpts
  364.   numeric accent_gap,mid_stem; mid_stem=2/3[stem,hi.stem];
  365.   if serifs:
  366.    pickup crisp.nib;
  367.    x[jj]'=hround(w-2hi.u)-.5mid_stem; x[jj]':= -x[jj]'+ 2/3[x[jj]',w-x[jj]'];
  368.    y[jj]'=h-.5mid_stem+eps-max(2/3[h,hi.x_height],hi.x_height+o+hair);
  369.    accent_gap=a_ht-(y[jj]'+.5mid_stem)-hi.x_height;
  370.    bot z[ii]=round(accent_hpos,
  371.     accent_gap+if is_cap: cap_height else: hi.x_height fi);
  372.    z[jj]=z[ii]+(z[jj]'
  373.     if is_cap: rotated (-the_cap_flat*(angle(z[jj]')-180)) fi);
  374.    numeric theta; theta=angle(z[ii]-z[jj])+90;
  375.    pos[jj](mid_stem,theta); pos[ii](hair,theta);
  376.   else:
  377.    pickup fine.nib;
  378.    lft x[jj]'l=-hround(.5w-1.25hi.u);
  379.    top y[jj]'=h-vround(2/3[h,hi.x_height]);
  380.    z[ii]'=origin; pos[jj]'(mid_stem,0); pos[ii]'(vair,0);
  381.    accent_gap=a_ht-y[jj]'-hi.x_height;
  382.    if is_cap:
  383.     numeric beta; beta=-the_cap_flat*(angle(z[jj]'-z[ii]')-180);
  384.     z[ii]=round(accent_hpos,accent_gap+cap_height);
  385.     z[jj]=z[ii]+(z[jj]' rotated beta);
  386.     y[jj]r=y[jj]l=y[jj]; y[ii]r=y[ii]l=y[ii];
  387.     for xx:=jj,ii: forsuffixes $:=l,r:
  388.      (z[xx]$-z[ii]) rotated -beta=whatever[z[jj]'$,z[ii]'$];
  389.     endfor\\ endfor
  390.    else:
  391.     for xx:=jj,ii: forsuffixes $:=r, ,l:
  392.      z[xx]$=z[xx]'$+round(accent_hpos,
  393.       accent_gap+if is_small_cap: cap_height else: x_height fi);
  394.     endfor\\ endfor
  395.    fi
  396.   fi
  397.  endgroup;
  398. enddef;
  399.  
  400. def put_gravis=
  401.  numeric accent_hpos;
  402.  accent_hpos=.5w + if is_cap: .75 else: .5 fi\\ u
  403.   if known hpos_corr: +hpos_corr fi;
  404.  fix_grav_pairs; % |fix_grav_pairs| uses private values of |w|, |h| \& |u|
  405.  numeric hpos_corr; % |hpos_corr| is local: forget its value
  406. % draw the diagonal:
  407.  if serifs:
  408.   pickup crisp.nib; filldraw circ_stroke (z[jj]e--z[ii]e);
  409.   z[jj].right=directionpoint down of (z[jj]r{z[jj]r-z[ii]r}..{z[ii]l-z[jj]l}z[jj]l);
  410.   z[jj].top=directionpoint left of (z[jj]r{z[jj]r-z[ii]r}..{z[ii]l-z[jj]l}z[jj]l);
  411.  else:
  412.   pickup fine.nib; filldraw stroke (z[jj]e--z[ii]e);
  413.   z[jj].right=z[jj].top=z[jj]r;
  414.  fi
  415. % adjust and save height (tho the height is never needed):
  416.  h:=if is_cap: y[jj].top else: a_ht fi; 
  417.  if known sharp_calc: saved_height:=h; fi
  418.  mark_height(a_ht#); 
  419.  penlabels([ii],[jj]);
  420. enddef;
  421. % ---------------------------------------------------------------------------
  422. %                           DOT ACCENT ACCESSORIES
  423. % ---------------------------------------------------------------------------
  424. %%% good penkind
  425. def put_dot (suffix penkind) (expr dd_) = % dot of the lowercase letter `i'
  426.  fix_virgin z;
  427.  numeric dd#; % sharp dot diameter
  428.  dd#=dd_; define_whole_blacker_pixels(dd);
  429. % adjust height temporarily:
  430.  h:=vround(if is_cap: (cap_height#+1.5u#+dd#)
  431.            elseif (charcode=oct"273") or (charcode=oct"012"): i_ht#(dd) 
  432.            fi\\ *hppp);
  433.  pickup penkind.nib; pos[jj](dd,90); pos[ii](dd,0);
  434.  x[jj]=x[ii]=good.x(.5w+if charcode=oct"233": .5 else: if charcode=oct"235": 0
  435.    else: .25 fi\\fi\\ u);
  436.  top y[jj]r=h+1; y[ii]=.5[y[jj]l,y[jj]r];
  437. % draw the dot:
  438.  dot([ii],[jj]);
  439. % dotted `Z' inherits the recently saved height (if known; usually the height
  440. % of the accented `Z') which allows to decrease by one the number of different
  441. % heights in a font; dotted `z' has the height of a lowercase `i' (exception:
  442. % caps and small caps)
  443.  if known saved_height: h:=saved_height; fi\\ mark_height(i_ht#(dd));
  444.  penlabels([ii],[jj]);
  445. enddef;
  446. % ---------------------------------------------------------------------------
  447. %                           L's CROSS ACCESSORIES
  448. % ---------------------------------------------------------------------------
  449. def put_cross(expr l_jut,r_jut) =
  450.  fix_virgin z;
  451.  numeric dd; dd=if is_cap: cap_bar else: bar fi;
  452.  numeric theta; theta=angle(11u#,.3[x_height#,cap_height#]);
  453.  pickup crisp.nib; pos[ii](dd,theta+90); pos[jj](dd,theta+90);
  454.  lft x[ii]r = hround(x1-l_jut)-eps;
  455.  rt x[jj]l = hround(x1+r_jut)+eps;
  456.  z[ii]-z[jj]=whatever*dir theta;
  457. % |.52| is one of CM (Computer Magic) numbers appearing in many CM programs,
  458. % among others in the programs for B, F, and H:
  459.  whatever[z[ii],z[jj]]=if not is_cap and hefty: top fi\\ 
  460.   (x1,if charcode=32: .3[x_height,asc_height-serif_drop] % tc blank sign
  461.       elseif charcode=147: .3x_height % tc recipe sign
  462.       else: .52cap_height fi\\);
  463. % before drawing the stroke improve discretization:
  464.  save eps_;
  465.  eps_:=y[ii]l-good.y(y[ii]l);
  466.  forsuffixes $:=l, ,r: y[ii]$:=y[ii]$-eps_; endfor
  467.  eps_:=y[jj]r-good.y(y[jj]r);
  468.  forsuffixes $:=l, ,r: y[jj]$:=y[jj]$-eps_; endfor
  469.  filldraw stroke z[ii]e--z[jj]e; % now draw the stroke
  470.  corrital z[jj]l; % correct italic correction
  471.  penlabels([ii],[jj]);
  472. enddef;
  473. % ---------------------------------------------------------------------------
  474. %                           OGONEK ACCESSORIES
  475. % ---------------------------------------------------------------------------
  476. % This part is admittedly sophisticated, however, a wide spectrum of
  477. % different ogonek shapes is in fact to be programmed: one shape is needed
  478. % for caps, another for `a' with ogonek, yet another for `e' with ogonek,
  479. % as they all have different joins. Moreover, a sansserif ogonek differs
  480. % significantly from a serif one, a bold ogonek from a non-bold, an ogonek
  481. % for hefty fonts should still be different. And if you take into account
  482. % that the basic font unit |u| may change during one session of font
  483. % generation (monospace and caps-small-caps) and that a few different
  484. % pens may be used to draw a single letter, you'll understand why so many
  485. % |if| ... |else:| ... |fi| commands are used in the following code.
  486. % Outer and inner edges of an ogonek (suffixed with |l| and |r|, resp.)
  487. % are single B\`ezier segments; the outer one, a path
  488. %    |p=z_a..controls z_b and z_c ..z_d|
  489. % is constructed as follows: given pairs |z_a|, |z_d|, angles |alpha_a|,
  490. % |alpha_d| and two numbers |x_down|, |y_right|, find pairs |z_b| and |z_c|
  491. % such that the path |p| has the following properties:
  492. %   (a) |direction p(z_a)=alpha_a|
  493. %   (b) |direction p(z_d)=alpha_d-180| 
  494. %   (c) |direction p(x_down,some_y)=down|
  495. %   (d) |direction p(some_x,y_right)=right|
  496. % The problem is solved using a ``double'' bisection method, provided 
  497. % that appropriate limits |z_b'|, |z_b''| and |z_c'|, |z_c''| for |z_b|
  498. % and |z_c|, respectively, are given; more precisely,
  499. %       |z_b=|$\lambda_b$|[z_b',zb'']| and |z_c=|$\lambda_c$|[z_c',zc'']|
  500. % is supposed to hold for given |z_b'|, |z_b''|, |z_c'|, |z_c''| and
  501. % some $0<\lambda_b,\lambda_c<1$.
  502. %
  503. % The inner edge is constructed by a careful modification of the outer one. 
  504. %
  505. % If a default behaviour of our program is not satisfying, the user may
  506. % assign a value to the following ``emergency'' parameters (provided E knows
  507. % what E is doing):
  508. %       |depth_corr|, |left_corr|, |top_breadth_corr|, |tip_breadth_corr|,
  509. %       |tip_xcorr|, |tip_ycorr|, |pre_angle|, |post_angle|,
  510. %       |pre_limit|, |post_limit|, |pre_lightness|, |post_lightness|,
  511. %       |pre_deflexion|, and |post_deflexion|.
  512. % Any of these parameters, if known while generating a font, is used instead
  513. % of a default setting. The parameters are accessed only via macros:
  514. %       |the_ogonek_depth#|, |the_left_pos|, |the_top_breadth_corr|,
  515. %       |the_tip_breadth_corr|, |the_tip_pos|,
  516. %       |the_pre_angle|, |the_post_angle|, |the_pre_limit|, |the_post_limit|,
  517. %       |the_pre_lightness|, |the_post_lightness|,
  518. %       |the_pre_deflexion|, and |the_post_deflexion|.
  519. % There is one sharp ogonek parameter, |ogonek_pen#|; a respective pen is
  520. % defined at the end of this file (and once again in POLKAP.MF after
  521. % |font_setup|) and used in the files PL_DL.MF, PL_ML.MF, PL_MLK.MF.
  522. % Any parameter may have its |lower| variant (see the file POLKAP.MF).
  523. % ---------------------------------------------------------------------------
  524. % two handy macros:
  525. vardef cross_point(expr a,b) (expr c,d) =
  526.  save z_; pair z_; z_=whatever[a,b]; z_=whatever[c,d]; z_
  527. % the crossing point of lines (not segments) |a--b| and |c--d| is returned
  528. enddef;
  529.  
  530. vardef touch_time(expr p,q) = % a variant of |intersectionpoint|
  531.  save x_,y_; (x_,y_)=p intersectiontimes q; if x_<0: 0 else: y_ fi
  532. enddef;
  533. % ---------------------------------------------------------------------------
  534. % the kernel routine for the ogonek:
  535. numeric x_down,x_down',y_right,y_right',alpha_a,alpha_d;
  536. pair z_a,z_b,z_b',z_b'',z_c,z_c',z_c'',z_d;
  537.  
  538. pair nz_,pz_;
  539. % with plain's |solve| embeded calls are not allowed, hence a bit tricky
  540. % variation:
  541. %%% known zsolve
  542. vardef zsolve@#(suffix z_)=
  543. % |@#| is the name of a real monotonic function; it is assumed that
  544. % |@#(z_')<=0|, |@#(z_'')>0| holds for given |z_'| and |z_''|
  545.  save nz_,pz_; pair nz_,pz_; % recursive calls are possible
  546.  nz_:=z_'; pz_:=z_'';
  547.  forever:
  548.   z_:=.5[nz_,pz_]; exitif abs(nz_-pz_)<=tolerance; % by default |tolerance=.1|
  549.   if @#(z_)<=0: nz_ else: pz_ fi :=z_;
  550.  endfor
  551. % on exit |z_| is (hopefully) near the point where |@#| changes from
  552. % negative to positive
  553. enddef;
  554.  
  555. vardef down_dir(expr z_b)=
  556.  zsolve right_dir(z_c); % here |z_c| is computed
  557.  lft(xpart(directionpoint down of (z_a..controls z_b and z_c..z_d)))-x_down
  558. enddef;
  559.  
  560. vardef right_dir(expr z_c)=
  561.  bot(ypart(directionpoint right of (z_a..controls z_b and z_c..z_d)))-y_right
  562. enddef;
  563. % ---------------------------------------------------------------------------
  564. % ogonek defaults:
  565. vardef the_ogonek_depth# = % sharp value
  566.  if known depth_corr: depth_corr* fi\\ desc_depth#
  567. enddef;
  568.  
  569. vardef the_left_pos =
  570.  if known left_corr: left_corr* fi
  571.   if monospace: 3.75 elseif serifs:
  572.    if hefty: 2.3 elseif is_bold: 1.7 else: 1.9 fi
  573.   else: % sansserif
  574.    if is_bold: 1.65 else: 1.55 fi\\ fi\\ hi.u
  575. enddef;
  576.  
  577. vardef the_tip_pos =
  578.   (if monospace: 1.9 elseif serifs: if hefty: 1.85
  579.    elseif is_bold: 1.75 else: 2 fi\\ else: % sansserif
  580.     if is_bold: 2.1 else: 1.95 fi\\ fi\\ hi.u,
  581.    if serifs:
  582.     if monospace: 1.25 elseif hefty: 1 elseif is_bold: .75 else: 1.45 fi
  583.    else: % sansserif
  584.     .45 fi\\ hi.u)
  585.    if known tip_xcorr: xscaled\\ tip_xcorr fi
  586.    if known tip_ycorr: yscaled\\ tip_ycorr fi
  587. enddef;
  588.  
  589. vardef the_top_breadth_corr =
  590.  if known top_breadth_corr: top_breadth_corr else:
  591.   if serifs: 1 elseif is_bold: 1.12 elseif is_cap: 1.06 else: .96 fi\\ fi
  592. enddef;
  593.  
  594. vardef the_tip_breadth_corr =
  595.  if known tip_breadth_corr: tip_breadth_corr else: 1 fi
  596. enddef;
  597.  
  598. vardef the_pre_angle = % refers to the outer edge
  599.  if known pre_angle: pre_angle else:
  600.   if serifs: if hefty: 208 elseif is_bold: 211 else: 214 fi\\ else: 211 fi
  601.  fi
  602. enddef;
  603.  
  604. vardef the_post_angle = % refers to the outer edge
  605.  if known post_angle: post_angle else:
  606.   if serifs: if monospace: 60 elseif hefty: 66 elseif is_bold: 55 else: 74 fi
  607.   else: 25 fi\\ fi
  608. enddef;
  609.  
  610. vardef the_pre_limit = % refers to the outer edge
  611.  if known pre_limit: pre_limit else: x_down-3.5hi.u fi
  612. enddef; 
  613.  
  614. vardef the_post_limit = % refers to the outer edge
  615.  if known post_limit: post_limit else: x_down-2hi.u fi
  616. enddef; 
  617.  
  618. vardef the_pre_lightness = % refers to the inner edge
  619.  if known pre_lightness: pre_lightness else:
  620.  if serifs and hefty: .97 elseif not serifs and is_bold: .6
  621.   elseif is_bold: .66  else: .78 fi\\ fi
  622. enddef;
  623.  
  624. vardef the_post_lightness = % refers to the inner edge
  625.  if known post_lightness: post_lightness else:
  626.   if serifs:
  627.     if hefty: .95 elseif is_bold: .66 else: .82 fi
  628.   else: % sansserif
  629.   .75 fi\\ fi
  630. enddef;
  631.  
  632. vardef the_post_deflexion = % refers to the inner edge
  633.  if known post_deflexion: post_deflexion elseif serifs and hefty: 0
  634.  else: -5 fi
  635. enddef;
  636.  
  637. vardef the_pre_deflexion = % refers to the inner edge
  638.  if known pre_deflexion: pre_deflexion
  639.   elseif known join_angle and not serifs:
  640.    if is_bold: -4 else: -2 fi\\ 
  641.   elseif not serifs: if is_bold: -8 else: -4 fi\\ else: 0 fi
  642. enddef;
  643. % ---------------------------------------------------------------------------
  644. %%% fine lo
  645. vardef lo suffix z = % in a way |lo| is a counterpart to |hi|
  646.  if is_small_cap: z_a+((z-z_a) scaled sqrt(body_height#/higher.body_height#))
  647.  else: z fi
  648. enddef;
  649. % ---------------------------------------------------------------------------
  650. % parameters to |put_ogonek|:
  651. numeric join_angle; % starting (inner) ogonek direction, if known
  652. numeric ogonek_breadth; % ogonek breadth at the tip
  653. % starting (inner for `e' with ogonek, otherwise outer) ogonek position:
  654. pair ogonek_pos;
  655. % ---------------------------------------------------------------------------
  656. def put_ogonek(suffix penkind) =
  657.  begingroup
  658.   if monospace:
  659. % excerpt from |mono_adjust|:
  660.    save u_; numeric u_; u_:=hi.u#; save u; u#:=u_;
  661.    numeric expansion_faktor;
  662.    mono_charwd#=2hi.letter_fit#+expansion_faktor*cap_A_wd#; % cap_A_wd=13u
  663.    hi.u:=u#*expansion_faktor*hppp;
  664. % now |u| is like in the letter `A'
  665.   fi
  666.  
  667.   fix_virgin z; pickup penkind.nib;
  668.  
  669. % `a' with ogonek attached to the hook deserves a special treatment:
  670.   if\\ (not is_small_cap) and (charcode=oct"241") and serifs and not is_bold:
  671.    if ypart(ogonek_pos)>.5penkind:
  672.     z[ii]~l=ogonek_pos;
  673.     pos[ii]~(max(the_top_breadth_corr*ogonek_breadth,penkind+epsilon),0);
  674.     ogonek_pos:=cross_point((0,.5penkind),(1,.5penkind))
  675.      (z[ii]~l,z[ii]~l+dir(the_pre_angle));
  676.    fi
  677.   fi
  678.  
  679. % similarly, `e' with ogonek deserves a special treatment:
  680.   if\\ (not is_small_cap) and (charcode=oct"246"):
  681.    if ypart(ogonek_pos)>.5penkind:
  682.     z[ii]~r=ogonek_pos;
  683.     pos[ii]~(max(the_top_breadth_corr*ogonek_breadth,penkind+epsilon),0);
  684.     ogonek_pos:=cross_point((0,.5penkind),(1,.5penkind))
  685.      (z[ii]~l,z[ii]~l+dir(join_angle));
  686.    fi
  687.   fi
  688.  
  689. % invariant: |ypart(ogonek_pos)|$\le$|.5penkind|;
  690. % moreover, for `A' and `E': |ypart(ogonek_pos)=.5penkind|
  691.  
  692. % OUTER EDGE:
  693.   alpha_a:=the_pre_angle; % starting direction
  694.   alpha_d:=180+the_post_angle; % ending direction
  695.   x_down:=if serifs: hround else: ceiling fi
  696.    (xpart(ogonek_pos)-the_left_pos); % left bound
  697.   y_right:=-vround(d+hi.o); % bottom bound
  698.   z_a:=(x_down+the_left_pos,ypart(ogonek_pos)); % starting point
  699.   z_d:=(xpart(z_a)-.5penkind,y_right+ypart(ogonek_pos))+
  700.    the_tip_pos; % ending point
  701. % guess the boundaries for control points:
  702.   z_b':=cross_point (z_a,z_a+dir alpha_a)
  703.    ((the_pre_limit,0),(the_pre_limit,1));
  704.   z_b'':=cross_point (z_b',z_a)\\ ((x_down,0),(x_down,1));
  705.   z_c':=cross_point (z_d,z_d+dir alpha_d)
  706.    ((the_post_limit,0),(the_post_limit,1));
  707.   z_c'':=cross_point (z_c',z_d)\\ ((0,y_right),(1,y_right));
  708. % THE PIVOT STEP OF THE OGONEK PROCEDURE, i.e.,
  709. % determine the control points (|z_b| and |z_c|) of the outer path:
  710.   zsolve down_dir(z_b); % |down_dir| calls `|zsolve right_dir(z_c)|'
  711.   x_down':=xpart(lft(directionpoint down of
  712.    (z_a..controls z_b and z_c..z_d)));
  713.   y_right':=ypart(bot(directionpoint right of
  714.    (z_a..controls z_b and z_c..z_d)));
  715.   if abs(x_down'-x_down,y_right'-y_right)>sqrt2:
  716.    message "ERROR: `ogonek' iteration hasn't converged! Final values:";
  717.    message "x_down="&decimal x_down'&" (should be "&decimal x_down&")";
  718.    message "y_right="&decimal y_right'&" (should be "&decimal y_right&")";
  719.    errhelp "Maybe Jackowski knows how to change them...";
  720.    errmessage "Probably, you have to change somehow the boundary values";
  721.   fi
  722.  
  723. % small caps have ogoneks a bit smaller:
  724.   z[ii]l=z_a; z[ii]'l=lo.z_b; z[jj]'l=lo.z_c; z[jj]l=lo.z_d;
  725.  
  726. % INNER EDGE:
  727.   pos[ii](max(the_top_breadth_corr*ogonek_breadth,penkind+epsilon),0);
  728.   pos[jj](max(the_tip_breadth_corr*ogonek_breadth,penkind+epsilon),
  729.    angle(direction 1 of (z_a..controls z_b and z_c..z_d))+
  730.     if serifs: 90 else: 80 fi);
  731.  
  732.   z[ii]'r=z[ii]r+((z[ii]'l-z[ii]l) scaled the_pre_lightness
  733.    rotated the_pre_deflexion);
  734.   z[jj]'r=z[jj]r+((z[jj]'l-z[jj]l) scaled the_post_lightness
  735.    rotated the_post_deflexion);
  736.  
  737. % trim the top of the ogonek, if necessary:
  738.   path ogonek.l, ogonek.r; numeric tt.r, tt.l;
  739.  
  740.   ogonek.l=if is_known z[ii]~: % minuscule with ogonek
  741.     z[ii]~l{dir if charcode=oct"241": the_pre_angle else: join_angle fi}..fi
  742.     z[ii]l..controls z[ii]'l and z[jj]'l..z[jj]l;
  743.   ogonek.r=if is_known z[ii]~: % ditto
  744.     z[ii]~r{dir if charcode=oct"241": the_pre_angle else: join_angle fi}..fi
  745.     z[ii]r..controls z[ii]'r and z[jj]'r..z[jj]r;
  746.  
  747.   tt.r=if serifs and (not is_small_cap) and (charcode=oct"241"):
  748.    touch_time(p.l,ogonek.r) else: 0 fi;
  749.   tt.l=if\\ (not is_small_cap) and (charcode=oct"246"):
  750.    touch_time(p.r,ogonek.l) else: 0 fi;
  751. % at last, draw the ogonek:
  752.    if ogonek_breadth>.5:
  753.     interim turningcheck:=0; filldraw
  754.     if\\ (not is_small_cap) and (charcode=oct"246"):
  755.      (point tt.r of ogonek.r){direction tt.r of ogonek.r}..{curl 1} fi
  756.     subpath (tt.l,length ogonek.l) of ogonek.l--
  757.     reverse(subpath (tt.r,length ogonek.r) of ogonek.r)
  758.     if is_small_cap or (charcode<>oct"246"): -- else: & fi\\ cycle;
  759. % the |draw| command covers with ink unwanted breaks:
  760.     pickup pensquare scaled (.5*sqrt2) rotated 45;
  761.      draw .5[z[ii]l,z[ii]r]..controls .5[z[ii]'l,z[ii]'r] and
  762.      .5[z[jj]'l,z[jj]'r].. .5[z[jj]l,z[jj]r];
  763.    else: % poor resolution:
  764.     pickup pensquare scaled (.5*sqrt2) rotated 45;
  765.     draw z[ii]l..controls z[ii]'l and z[jj]'l..z[jj]l;
  766.    fi
  767.  
  768.   numeric join_angle, ogonek_breadth; pair ogonek_pos; % all they are local
  769.  
  770.   penlabels([ii],[jj]);
  771.  
  772.  endgroup
  773. enddef;
  774. %*******************************************************************************
  775. %
  776. % This was csaccent.mf in text format, as of 89/05/08
  777. % written by P. Novak, Prague
  778. % Czech and Slovak letters with accents
  779. % Changed paths for acute and hachek accent added 26/04/92, 11/08/92
  780. % Accent definitions   |lc_circle_accent| modified
  781. %                      |uc_Circle_accent| added for Duerer font
  782. %
  783. %  7 May 1995 did whole sale surgery to this part. Moved parameters to
  784. %    dxpseudo.mf to be able to manipulate them from there. The Acute 
  785. %    accent is done the polish way, therefore removed all acute related
  786. %    macros. Pseudoparametrised all kinds of |dot_diam|. 
  787. % 17 Jun 1995 adjusted hachek height parameters to blend better with acute
  788. %    parameters. Removed lots of stuff not used by the dc and tc fonts.
  789. % 17 Jul 1995 corrected uppercase hachek height for sans serif case   
  790. %    Removed many macros, which aren't used anymore
  791. % 23 Aug 1996 Adjusted |lc_hachek_accent| for dcsx font
  792. % 23 Dec 1996 Done provisions for small caps fonts, consequently
  793. %    applied |hi.|, replaced |curve| by |cap_curve| for |uc_hachek_accent|,
  794. %    adjusted numeric factors to the usually higher value of |cap_curve|.
  795. % 19 Jan 1997 The |uc_hacheck_accent| comes out too high, because of 
  796. %    unwanted white space above it. Changed appropriately.
  797. %===============================================================================
  798.  
  799. def lc_hachek_accent(expr ref) =
  800.    if serifs:
  801.        pickup crisp.nib;
  802.        pos52'(0.75[vair,curve],90);
  803.        pos52(0.75[vair,curve],90);
  804.        x52=good.x ref; 
  805.        x52-x51=x53-x52=good.x if hach_sharp:2.5 else:3 fi 
  806.                               accent_u-accent_thin;
  807.        top y52' = top y51 = top y53 = lc_hachek_height;
  808.      if hach_sharp: 
  809.        y52=max(2/3[h,hi.x_height],hi.x_height+o+hair); % lower point
  810.        pos51(1.5stem,0); pos53(accent_thin,180); 
  811.      else:
  812.        0.5[y52,y52r] = 0.5[hi.x_height,y52']; 
  813.        pos51(accent_thin,angle(z52-z51)+90);
  814.        pos53(accent_thin,angle(z53-z52)+90); 
  815.      fi
  816.        filldraw stroke z51e -- z52e -- z53e;
  817.     else:
  818.        pickup fine.nib;
  819.        pos51(vair,0);
  820.        pos53(vair,0);
  821.        x52=good.x ref;
  822.        x52-lft x51=rt x53-x52= hround(1.25accent_u + vair);
  823.        pos52(stem,0);
  824. %       bot y52=vround(0.3[x_height,lc_hachek_height]);
  825.        bot y52=vround(max(2/3[h,hi.x_height],hi.x_height+o+hair));
  826.        top y51 = top y53 = lc_hachek_height;
  827.        z50 = whatever[z51r,z52r] = whatever[z52l,z53l];
  828.        y54l=y54r=y52;
  829.        x54l=good.x .2[x52l,x52];
  830.        x54r-x52 = x52-x54l;
  831.        filldraw z54l -- z51l-- z51r -- z50 -- z53l -- z53r -- z54r -- cycle;
  832.     fi
  833.     penlabels(50,51,52,52',53,54);
  834. enddef;
  835.  
  836. def dtl_hachek(text x_ref,y_ref) =
  837. pickup fine.nib;
  838.   pickup fine.nib;
  839.   x51=hround(x_ref); y51=vround(y_ref);
  840.   comma(51,q,pdot_diam,.25accent_u,2/3comma_depth);
  841.   penlabels(51);
  842. enddef;
  843.  
  844. def uc_hachek_accent(expr ref) =
  845.  if serifs:
  846.        pickup crisp.nib;
  847.        pos52'(0.5[vair,cap_curve],90);
  848.        pos52(0.5[vair,cap_curve],90);
  849.        x52=good.x ref; 
  850.        x52-x51=x53-x52=good.x 3accent_u-accent_thin;
  851.        top y52' = top y51 = top y53 =        % upper points
  852.         uc_acc_height-.5[vair,cap_curve]+eps
  853.         -max(2/3[uc_acc_height,hi.x_height],hi.x_height+o+hair)+cap_height;
  854.      if hach_sharp:
  855.        y52=max(2/3[uc_acc_height,hi.x_height],hi.x_height+o+hair)
  856.            -hi.x_height+cap_height;           % lower point
  857.        pos51(cap_stem,0); pos53(2accent_thin,180); 
  858.      else:
  859.        0.5[y52,y52r] = 
  860.       if not hefty:
  861.         max(2/3[uc_acc_height,hi.x_height],hi.x_height+o+hair)
  862.             -hi.x_height+cap_height;
  863.       else:
  864.         max(2/3[uc_acc_height,hi.x_height],hi.x_height+o)
  865.             -hi.x_height+cap_height-hair;
  866.       fi
  867.        pos51(accent_thin,angle(z52-z51)+90);
  868.        pos53(accent_thin,angle(z53-z52)+90);
  869.      fi
  870.        filldraw stroke z51e -- z52e -- z53e;
  871.  else:
  872.        pickup fine.nib;
  873.        pos51(vair,0);
  874.        pos53(vair,0);
  875.        x52=good.x ref;
  876.        x52-x51=x53-x52= 1.75accent_u + .5vair;
  877.        pos52(cap_stem,0);
  878.        bot y52= cap_height + .5 accent_gap;
  879.        top y51 = top y53 = cap_height + acc_height;
  880.        z50 = whatever[z51r,z52r] = whatever[z52l,z53l];
  881.        y54l=y54r=y52;
  882.        x54l=good.x .2[x52l,x52];
  883.        x54r-x52 = x52-x54l;
  884.        filldraw z54l -- z51l-- z51r -- z50 -- z53l -- z53r -- z54r -- cycle;
  885.  fi
  886. penlabels(50,51,52,52',53,54);
  887. enddef;
  888.  
  889. endinput;
  890. %%
  891.